package com.alks.function.service.impl.stitch;

import com.alks.common.data.thread.UserIdThread;
import com.alks.common.service.RedisService;
import com.alks.common.utils.beanutils.BeanUtil;
import com.alks.common.utils.beanutils.ObjectUtils;
import com.alks.entity.data.entity.*;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.ServiceErrorException;
import com.alks.function.data.dto.chengKong.produce.*;
import com.alks.function.data.dto.produce.*;
import com.alks.function.data.request.produce.PcStitchBarcodeHeadListRequest;
import com.alks.function.data.request.produce.StitchScanRequest;
import com.alks.function.mapper.SdCompanyMapper;
import com.alks.function.mapper.chengKong.PcLotHeadMapper;
import com.alks.function.mapper.pcfactoryquery.FT_QR_PcStitchDetailAttachMapper;
import com.alks.function.mapper.pcfactoryquery.FT_QR_PcStitchDetailMapper;
import com.alks.function.mapper.pcfactoryquery.FT_QR_PcStitchFrozenMapper;
import com.alks.function.mapper.pcfactoryquery.FT_QR_PcStitchStatusMapper;
import com.alks.function.mapper.produce.PcStitchBarcodeHeadMapper;
import com.alks.function.service.stitch.StitchCollectService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.UncategorizedSQLException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@RequiredArgsConstructor
public class StitchCollectServiceImpl implements StitchCollectService {

    private final PcStitchBarcodeHeadMapper pcStitchBarcodeHeadMapper;
    private final PcLotHeadMapper pcLotHeadMapper;
    private final RedisService redisService;
    private final FT_QR_PcStitchDetailMapper detailMapper;
    private final SdCompanyMapper sdCompanyMapper;
    private final FT_QR_PcStitchDetailAttachMapper detailAttachMapper;
    private final FT_QR_PcStitchStatusMapper statusMapper;

    private final RedisTemplate redisTemplate;

    private final FT_QR_PcStitchFrozenMapper pcStitchFrozenMapper;

    /**
     * 扫码:收发料
     *
     * @param request
     * @param language
     * @return
     */
    @Override
    @Transactional
    public ResponseInfo stitchScanIAndO(StitchScanRequest request, String language) {
        long start = System.currentTimeMillis();

        String companyId = UserIdThread.get().getCompanyId();
        String flag = request.getFlag();

        if (request.getBarcode() == null || request.getBarcode().isEmpty()){
            //throw  new ServiceErrorException("条码不能为空!");
            throw  new ServiceErrorException(getMessage("条码不能为空！","1.Mã vạch không thể trống rỗng",language));
        }
        if(request.getCollectPos() == null || request.getCollectPos().isEmpty()){
            //throw  new ServiceErrorException("设备编号不能为空！");
            throw  new ServiceErrorException(getMessage("设备编号不能为空！","2.Số thiết bị không thể trống",language));
        }
        if(!request.getProcessName().equals("针车")){
            //throw  new ServiceErrorException("请选择采集类别！");
            throw  new ServiceErrorException(getMessage("请选择采集类别！","3.Hãy chọn loại thu thập",language));
        }
        if(flag == null || flag.isEmpty()){
            //throw  new ServiceErrorException("请选择收料或者发料类型！");
            throw  new ServiceErrorException(getMessage("请选择收料或者发料类型！","4.Hãy chọn loại vật liệu nhận hoặc gửi",language));
        }

        System.out.println("开始扫描:" + request.getBarcode() + "  ,设备编号:" + request.getCollectPos() + ",类型:" + flag);
            /*获取扫描的数据*/
            PcStitchBarcodeHeadListRequest headRequest = new PcStitchBarcodeHeadListRequest();
            headRequest.setBarcode(request.getBarcode());
            headRequest.setCompanyId(companyId);
            List<PcStitchBarcodeHeadListDto> list = pcStitchBarcodeHeadMapper.getPcStitchBarcodeHeadList(headRequest);
            //判断条码是否正确
            if (ObjectUtils.isEmpty(list)) {
                //throw  new ServiceErrorException("扫描条码错误或不存在!");
                throw  new ServiceErrorException(getMessage("扫描条码错误或不存在！","5.Quét mã vạch sai hoặc không có",language));
            }
            //扫过的条码不能再扫一边
            PcStitchBarcodeHeadListDto barcodeDto = list.get(0);
            if(barcodeDto.getPrintFlag() == null){
                //throw  new ServiceErrorException("该条码暂未打印！");
                throw  new ServiceErrorException(getMessage("该条码暂未打印！","6.Mã vạch chưa được in",language));
            }

            //新增冻结，只有入库的时候提示,如果这个标签的指令冻结了无法入库
            if(flag.equals("I")){
                List<PcStitchFrozen> pcStitchFrozenList = pcStitchFrozenMapper.selectList(new LambdaQueryWrapper<PcStitchFrozen>()
                        .in(PcStitchFrozen::getLotNo, barcodeDto.getLotNo())
                        .eq(PcStitchFrozen::getCompanyId,companyId)
                );
                if(ObjectUtils.isNotEmpty(pcStitchFrozenList)){
                    throw  new ServiceErrorException(getMessage("该指令已被冻结，无法入库！","20.Chỉ thị đã bị đóng băng và không thể vào kho",language));
                }
            }


            //如果没有入库，就出库，会提示该材料未入库，请先做入库处理
            if(flag.equals("O") && barcodeDto.getInFlag() == null){
                //throw  new ServiceErrorException("该条码未入库，请先做入库处理！");
                throw  new ServiceErrorException(getMessage("该条码未入库，请先做入库处理！","7.Mã vạch không được nhập, xin vui lòng nhập",language));
            }

            //查询是否扫描过
            PcStitchBarcodeCollect collect = pcStitchBarcodeHeadMapper.getPcStitchBarcodeCollect(request);
            if(collect != null){
                if(flag.equals("I")){
                    //throw  new ServiceErrorException("收料：该条码已扫过!");
                    throw  new ServiceErrorException(getMessage("收料：该条码已扫过!","8.Nhận: mã vạch đã được quét",language));
                }else{
                    //throw  new ServiceErrorException("发料：该条码已扫过!");
                    throw  new ServiceErrorException(getMessage("发料：该条码已扫过!","9.Gửi: mã vạch đã được quét",language));
                }
            }

            /*处理收集数据*/
            //扫描头和扫描明细
            PcStitchBarcodeDto stitchDto = new PcStitchBarcodeDto();
            BeanUtils.copyProperties(barcodeDto, stitchDto);
            stitchDto.setBarcode(request.getBarcode());
            LocalDateTime now = LocalDateTime.now();
            if (flag.equals("I")) { //收料
                stitchDto.setInFlag("Y");
                stitchDto.setInQty(barcodeDto.getCaseQty());
                stitchDto.setInTime(now);
            } else if (flag.equals("O")){   //发料
                stitchDto.setDeptNo(request.getDeptNo());   //发料是选择的部门
                stitchDto.setDeptName(request.getDeptName());
                stitchDto.setOutFlag("Y");
                stitchDto.setOutQty(barcodeDto.getCaseQty());
                stitchDto.setOutTime(now);
            }
            stitchDto.setCompanyId(companyId);
            stitchDto.setSlipType(flag);
            stitchDto.setCollectType("S");
            stitchDto.setCollectTime(now);
            stitchDto.setQty(barcodeDto.getCaseQty());//明细收集的数量
            stitchDto.setCollectPos(request.getCollectPos());
            //区分公司
            stitchDto.setStkName(companyId.equals("BF") ? "荣信" : "荣越");
            stitchDto.setPrintFlag(null);   //此时没有打印收据
            stitchDto.setPrintTime(null);
            stitchDto.setPart(getMessage("鞋面","Đôi giày gặp nhau",language));
            stitchDto.setLsNo(barcodeDto.getLsNo());

        // 获取指令号码
        List<PcLotDetailDto2> codeDetails = pcLotHeadMapper.getCodeDetails4(stitchDto.getLotNo(), companyId,stitchDto.getSizeNo());
        if(ObjectUtils.isEmpty(codeDetails)){
            //throw new ServiceErrorException("指令" + stitchDto.getLotNo() + "没有尺码映射");
            throw  new ServiceErrorException(getMessage("指令" + stitchDto.getLotNo() + "没有尺码映射","10.Hướng dẫn" + stitchDto.getLotNo() + "Không có kích thước bản đồ",language));
        }
            

        //上锁
        String lockKey = "StitchScanOld:" + companyId + ":" + request.getFlag() + ":" + barcodeDto.getLotNo() + ":" + barcodeDto.getDeptNo() + ":" + barcodeDto.getSizeNo() ;
        String lockValue = UUID.randomUUID().toString();
        Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 5, TimeUnit.SECONDS);
        if (!isLocked) {
            //throw new ServiceErrorException("系统处理数据中,请稍后重试!");
            throw  new ServiceErrorException(getMessage("系统处理数据中,请稍后重试！","11.Hệ thống xử lý dữ liệu, xin vui lòng thử lại sau",language));
        }
        try {

            /*数据库*/
            //1.更新标签头表 PC_STITCH_BARCODE_HEAD
            int count1 = pcStitchBarcodeHeadMapper.updatePcStitchBarcodeHeadByScan(stitchDto);
            //2.新增收集表 PC_STITCH_BARCODE_COLLECT
            int count2 = 0;
            try {
                count2 = pcStitchBarcodeHeadMapper.insertPcStitchBarcodeCollect(stitchDto);
                log.info("3.时间：{},条码{},收发料类型：{},PC_STITCH_BARCODE_COLLECT的收发料数量：{}",now,stitchDto.getBarcode(),flag,barcodeDto.getCaseQty());
            } catch (Exception e) {
                log.info("插入收集明细表失败！该条码已扫过");
                //throw new ServiceErrorException("该条码已扫过");
                throw  new ServiceErrorException(getMessage("该条码已扫过","12.Mã vạch đã được quét",language));
            }

            /*获取待写入鞋面收发数据*/
            /*查询针车入库表是否已经存在：（缴库单位，指令，收发料，今天）有没有入库*/
            //3.查询PC_STITCH_DETAIL有没有数据
            List<PcStitchDetail> details= detailMapper.queryStitchDetail2(stitchDto);
            int count3 = 0;
            int count4 = 0;
            if(ObjectUtils.isEmpty(details)) {
                //今天还没有收 PC_STITCH_DETAIL
                PcStitchDetail detail = BeanUtil.copyBean(stitchDto, PcStitchDetail.class);
                detail.setSlipDate(LocalDate.from(now));
                detail.setSysDate(now);
                detail.setSysUser(request.getCollectPos());
                detail.setUpdateDate(now);
                detail.setUpdateUser(request.getCollectPos());
                detail.setCompanyId(companyId);
                detail.setOutDept(0);
                detail.setPrintFlag(null);
                String slipNo = redisService.slipNoCreatByTime("XM");  //第一次创建slipNo
                detail.setSlipNo(slipNo);
                detail.updateQty(codeDetails.get(0).getRowNum(),barcodeDto.getCaseQty());
                log.info("4.时间：{},条码{},收发料类型：{},PC_STITCH_DETAIL的收发料数量：{},qty(?):{}",now,stitchDto.getBarcode(),flag,barcodeDto.getCaseQty());
                count3 = detailMapper.insert(detail);
                //新增到 PC_STITCH_DETAIL_ATTACH
                PcStitchDetailAttach detailAttach = new PcStitchDetailAttach();
                BeanUtil.copyProperties(stitchDto, detailAttach);
                detailAttach.setSeqNo( barcodeDto.getSizeSeq());//鞋码序号
                detailAttach.setSlipNo(slipNo);
                detailAttach.setSlipDate(LocalDate.from(now));
                detailAttach.setQty(barcodeDto.getCaseQty()); //和收集表中扫到的的用量保持一致
                detailAttach.setStkName(companyId.equals("BF") ? "荣信" : "荣越");
                detailAttach.setSysDate(now);
                detailAttach.setSysUser(request.getCollectPos());
                detailAttach.setUpdateDate(now);
                detailAttach.setUpdateUser(request.getCollectPos());
                log.info("5.时间：{},条码{},收发料类型：{},PC_STITCH_DETAIL的收发料数量：{},鞋码:{}",now,stitchDto.getBarcode(),flag,barcodeDto.getCaseQty(),barcodeDto.getSizeSeq());
                //count4 = detailAttachMapper.insert(detailAttach);
                try{
                    count4 = detailAttachMapper.insert(detailAttach);
                }catch (UncategorizedSQLException e) {
                    //handleDatabaseException(e, "新增 PC_STITCH_DETAIL_ATTACH失败");
                     handleDatabaseException(e, getMessage("PC_STITCH_DETAIL_ATTACH 新增失败","13.PC_STITCH_DETAIL_ATTACH Thêm thất bại",language));
                }catch (Exception e) {
                    log.error("新增 PC_STITCH_DETAIL_ATTACH失败: ", e);
                    //throw new ServiceErrorException(" PC_STITCH_DETAIL_ATTACH新增失败:{}"); // 或者根据需要抛出其他异常
                    throw  new ServiceErrorException(getMessage("PC_STITCH_DETAIL_ATTACH 新增失败:{}","13.PC_STITCH_DETAIL_ATTACH Thêm thất bại:{}",language));
                }
            }else if(ObjectUtils.isNotEmpty(details)){
                //今天已经收了 PC_STITCH_DETAIL
                PcStitchDetail detail = details.get(0);
                detail.updateQty(codeDetails.get(0).getRowNum(),barcodeDto.getCaseQty());
                String slipNo = detail.getSlipNo(); //取已有的slipNo
                detail.setUpdateDate(now);
                detail.setUpdateUser(request.getCollectPos());
                log.info("4.时间：{},条码{},收发料类型：{},PC_STITCH_DETAIL的收发料数量：{},qty(?):{}",now,stitchDto.getBarcode(),flag,barcodeDto.getCaseQty(),barcodeDto.getSizeNo());
                count3 = detailMapper.updateQty(detail);

                // 查询 PC_STITCH_DETAIL_ATTACH 有没有数据
                //4.判断这个鞋码有没有收到
                stitchDto.setSlipNo(slipNo);
                List<PcStitchDetailAttach> detailAttachs = detailAttachMapper.queryStitchDetailAttach(stitchDto);
                if(ObjectUtils.isEmpty(detailAttachs) ){
                    //没有收到这个鞋码，新增入 PC_STITCH_DETAIL_ATTACH
                    PcStitchDetailAttach detailAttach = new PcStitchDetailAttach();
                    BeanUtil.copyProperties(stitchDto, detailAttach);
                    detailAttach.setSeqNo(barcodeDto.getSizeSeq());//鞋码
                    detailAttach.setSlipNo(slipNo);
                    detailAttach.setSlipDate(LocalDate.from(now));
                    detailAttach.setQty(barcodeDto.getCaseQty()); //和收集表中扫到的的用量保持一致
                    detailAttach.setStkName(companyId.equals("BF") ? "荣信" : "荣越");
                    detailAttach.setSysDate(now);
                    detailAttach.setSysUser(request.getCollectPos());
                    detailAttach.setUpdateDate(now);
                    detailAttach.setUpdateUser(request.getCollectPos());
                    log.info("5.时间：{},条码{},收发料类型：{},PC_STITCH_DETAIL的收发料数量：{},鞋码:{}",now,stitchDto.getBarcode(),flag,barcodeDto.getCaseQty(),barcodeDto.getSizeSeq());
                    //count4 = detailAttachMapper.insert(detailAttach);
                    try{
                        count4 = detailAttachMapper.insert(detailAttach);
                    }catch (UncategorizedSQLException e) {
                        //handleDatabaseException(e, "PC_STITCH_DETAIL_ATTACH 新增失败");
                        handleDatabaseException(e, getMessage("PC_STITCH_DETAIL_ATTACH 新增失败","13.PC_STITCH_DETAIL_ATTACH Thêm thất bại",language));
                    }catch (Exception e) {
                        log.error("新增 PC_STITCH_DETAIL_ATTACH失败: ", e);
                        //throw new ServiceErrorException("PC_STITCH_DETAIL_ATTACH 新增失败:{}"); // 或者根据需要抛出其他异常
                        throw  new ServiceErrorException(getMessage("PC_STITCH_DETAIL_ATTACH 新增失败:{}","13.PC_STITCH_DETAIL_ATTACH Thêm thất bại:{}",language));
                    }
                }else if(ObjectUtils.isNotEmpty(detailAttachs)){
                    //收过了这个鞋码，更新用量 PC_STITCH_DETAIL_ATTACH
                    PcStitchDetailAttach attach = detailAttachs.get(0);
                    attach.setQty(attach.getQty() + barcodeDto.getCaseQty());
                    attach.setSeqNo(barcodeDto.getSizeSeq());//鞋码序号
                    attach.setUpdateUser(request.getCollectPos());
                    log.info("5.时间：{},条码{},收发料类型：{},PC_STITCH_DETAIL的收发料数量：{},鞋码:{}",now,stitchDto.getBarcode(),flag,barcodeDto.getCaseQty(),barcodeDto.getSizeSeq());
                    //count4 = detailAttachMapper.updateQty(attach);
                    try{
                        count4 = detailAttachMapper.updateQty(attach);
                    }catch (UncategorizedSQLException e) {
                        //handleDatabaseException(e, "PC_STITCH_DETAIL_ATTACH 更新失败");
                        handleDatabaseException(e, getMessage("PC_STITCH_DETAIL_ATTACH 更新失败","14.PC_STITCH_DETAIL_ATTACH Cập nhật thất bại",language));
                    }catch (Exception e) {
                        log.error("更新 PC_STITCH_DETAIL_ATTACH失败: ", e);
                        //throw new ServiceErrorException("PC_STITCH_DETAIL_ATTACH 更新失败:{}"); // 或者根据需要抛出其他异常
                        throw  new ServiceErrorException(getMessage("PC_STITCH_DETAIL_ATTACH 更新失败:{}","14.PC_STITCH_DETAIL_ATTACH Cập nhật thất bại:{}",language));
                    }
                }else{
                    //throw new ServiceErrorException("鞋面入库明细表查找异常");
                    throw  new ServiceErrorException(getMessage("鞋面入库明细表查找异常","15.Danh sách truy cập vào kho lưu trữ để tìm các ngoại lệ",language));
                }
            }else{
                //throw new ServiceErrorException("鞋面入库表查找异常");
                throw  new ServiceErrorException(getMessage("鞋面入库表查找异常","16.Truy cập vào bảng tìm kiếm ngoại lệ",language));
            }


            //查询这个pos机器获得的数据，该收集表中该部门和指令未打印单据的总数----现在不看pos机器编码了
            PcStitchBarcodeDto printLot = pcStitchBarcodeHeadMapper.queryCollectStitchByLot(stitchDto);
            int qtyCount ;
            if (printLot != null){
                //Integer qty = printLot.getQty();
                //qtyCount = (qty == null ? barcodeDto.getCaseQty() : (qty + barcodeDto.getCaseQty()));
                qtyCount = printLot.getQty();
            }else{
                qtyCount = barcodeDto.getCaseQty();
            }

            HashMap mapResult = new HashMap<>();
            mapResult.put("barcodeDto", stitchDto);
            //累计收发料双数
            mapResult.put("qtyCount", qtyCount);

            //long executionTime = System.currentTimeMillis() - start;
            //System.out.println(executionTime + "ms");

            if(count1>0 && count2>0 && count3>0 && count4>0 ){
                //扫码成功后，会显示当前扫码信息
                if(flag.equals("I")){
                    //mapResult.put("msg", "收料成功！");
                    mapResult.put("msg", getMessage("收料成功！","200.Nhận thành công",language));
                    return ResponseInfo.ok(mapResult);
                }else{
                    //mapResult.put("msg", "发料成功！");
                    mapResult.put("msg", getMessage("发料成功！","201.Tài liệu thành công",language));
                    return ResponseInfo.ok(mapResult);
                }
            }else{
                //throw  new ServiceErrorException("收料或发料失败");
                throw  new ServiceErrorException(getMessage("收料或发料失败","17.Nhận hoặc gửi thất bại",language));
            }


        } finally {
            // 检查并释放锁
            String existingValue = (String) redisTemplate.opsForValue().get(lockKey);
            if (lockValue.equals(existingValue)) {
                redisTemplate.delete(lockKey); // 释放锁
            }
            long executionTime = System.currentTimeMillis() - start;
            System.out.println(executionTime + "ms");
        }

    }

    /**
     * 扫码:收料
     *
     * @param request
     * @param language
     * @return
     */
    @Override
    @Transactional
    public ResponseInfo stitchScanIn(StitchScanRequest request, String language) {
        long start = System.currentTimeMillis();


        String companyId = UserIdThread.get().getCompanyId();
        if (request.getBarcode() == null) {
            throw  new ServiceErrorException("条码不能为空!");
        }
        if(request.getCollectPos() == null){
            throw  new ServiceErrorException("设备编号不能为空！");
        }
        if(!request.getProcessName().equals("针车")){
            throw  new ServiceErrorException("请选择采集类别！");
        }
        if(request.getFlag() == null || !request.getFlag().equals("I")){
            throw  new ServiceErrorException("请选择收料类型！");
        }

        /*获取扫描的数据*/
        PcStitchBarcodeHeadDto barcodeDto = pcStitchBarcodeHeadMapper.getPcStitchBarcodeHead(companyId,request.getBarcode());
        //判断条码是否正确
        if (barcodeDto == null) {
            throw  new ServiceErrorException("未在本系统找到该条码!");
        }

        //新增冻结判断
        List<PcStitchFrozen> pcStitchFrozenList = pcStitchFrozenMapper.selectList(new LambdaQueryWrapper<PcStitchFrozen>()
                .in(PcStitchFrozen::getLotNo, barcodeDto.getLotNo())
                .eq(PcStitchFrozen::getCompanyId,companyId)
        );
        if(ObjectUtils.isNotEmpty(pcStitchFrozenList)){
            throw  new ServiceErrorException(getMessage("该指令已被冻结，无法入库！","20.Chỉ thị đã bị đóng băng và không thể vào kho",language));
        }

        if(barcodeDto.getPrintFlag() == null){
            throw  new ServiceErrorException("未在本系统找到该条码打印标记，请检查！");
        }
        //查询是否扫描过
        PcStitchBarcodeCollect collect = pcStitchBarcodeHeadMapper.getPcStitchBarcodeCollect(request);
        if(collect != null && collect.getSlipType() != null && !collect.getSlipType().equals("I")){
            throw  new ServiceErrorException("收料：该条码已扫过!");
        }

        /*处理收集数据*/
        //扫描头和扫描明细
        PcStitchBarcodeDto stitchDto = new PcStitchBarcodeDto();
        BeanUtils.copyProperties(barcodeDto, stitchDto);
        LocalDateTime now = LocalDateTime.now();
        stitchDto.setCompanyId(companyId);
        stitchDto.setInFlag("Y");
        stitchDto.setInQty(barcodeDto.getCaseQty());
        stitchDto.setInTime(now);
        stitchDto.setSlipType(request.getFlag());
        stitchDto.setQty(barcodeDto.getCaseQty());//明细收集的数量
        stitchDto.setCollectPos(request.getCollectPos());
        stitchDto.setStkName("荣信");
        stitchDto.setPart("鞋面");
        stitchDto.setCollectType("S");
        stitchDto.setLsNo(barcodeDto.getLsNo());

        //上锁
        String lockKey = "StitchScan:" + companyId + ":" + request.getFlag() + ":" + barcodeDto.getLotNo() + ":" + barcodeDto.getDeptNo() + ":" + barcodeDto.getSizeNo() ;
        String lockValue = UUID.randomUUID().toString();
        Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 2, TimeUnit.SECONDS);
        if (!isLocked) {
            throw new ServiceErrorException("系统处理数据中,请稍后重试!");
        }

        try {

            /*处理收集表*/
            //1.更新标签头表 PC_STITCH_BARCODE_HEAD
            int count1 = pcStitchBarcodeHeadMapper.updatePcStitchBarcodeHeadByScan(stitchDto);
            //加入收集明细表
            //2.新增收集表 PC_STITCH_BARCODE_COLLECT
            int count2 = 0;
            try {
                count2 = pcStitchBarcodeHeadMapper.insertPcStitchBarcodeCollect(stitchDto);
            } catch (Exception e) {
                log.info("插入收集明细表失败！该条码已扫过");
                throw new ServiceErrorException("该条码已扫过");
            }

            // 获取指令号码
            List<PcLotDetailDto2> codeDetails = pcLotHeadMapper.getCodeDetails4(stitchDto.getLotNo(), companyId,stitchDto.getSizeNo());
            if(ObjectUtils.isEmpty(codeDetails)){
                throw new ServiceErrorException("指令" + stitchDto.getLotNo() + "没有尺码映射");
            }

            /*获取鞋面收发数据*/
            /*查询针车入库表是否已经存在：（缴库单位，指令，收发料，今天）有没有入库*/
            //3.查询 PC_STITCH_DETAIL 有没有数据
            List<PcStitchDetail> details= detailMapper.queryStitchDetail2(stitchDto);
            int count3 = 0;
            int count4 = 0;
            if(ObjectUtils.isEmpty(details)) {  //今天还没有收 PC_STITCH_DETAIL
                // 新增 PC_STITCH_DETAIL
                PcStitchDetail detail = new PcStitchDetail();
                BeanUtil.copyProperties(stitchDto, detail);
                detail.setSlipDate(LocalDate.from(now));
                detail.setSysDate(now);
                detail.setSysUser(request.getCollectPos());
                detail.setOutDept(0);
                detail.setPrintFlag(null);
                detail.setUpdateUser(request.getCollectPos());
                String slipNo = redisService.slipNoCreatByTime("XM");  //第一次创建slipNo
                detail.setSlipNo(slipNo);
                detail.updateQty(codeDetails.get(0).getRowNum(),stitchDto.getCaseQty());
                count3 = detailMapper.insert(detail);
                //新增 PC_STITCH_DETAIL_ATTACH
                PcStitchDetailAttach attach = new PcStitchDetailAttach();
                BeanUtil.copyProperties(stitchDto, attach);
                attach.setSeqNo( barcodeDto.getSizeSeq());  //鞋码序号
                attach.setSlipNo(slipNo);
                attach.setSlipDate(LocalDate.from(now));
                attach.setUpdateDate(now);
                attach.setSysDate(now);
                attach.setSysUser(request.getCollectPos());
                attach.setUpdateUser(request.getCollectPos());
                attach.setQty(barcodeDto.getCaseQty()); //和收集表中扫到的的用量保持一致
                attach.setStkName("荣信");
                count4 = detailAttachMapper.insert(attach);
            }else if(ObjectUtils.isNotEmpty(details)){  //今天收了 PC_STITCH_DETAIL
                //更新 PC_STITCH_DETAIL
                PcStitchDetail detail = details.get(0);
                detail.setUpdateUser(request.getCollectPos());
                detail.updateQty(codeDetails.get(0).getRowNum(),stitchDto.getCaseQty());
                String slipNo = detail.getSlipNo(); //取已有的slipNo
                count3 = detailMapper.updateQty(detail);
                // 查询 PC_STITCH_DETAIL_ATTACH 有没有数据 （缴库单位，指令，收发料，今天，鞋码）
                //4. 判断这个鞋码有没有收到
                stitchDto.setSlipNo(slipNo);
                List<PcStitchDetailAttach> detailAttachs = detailAttachMapper.queryStitchDetailAttach(stitchDto);
                if(ObjectUtils.isEmpty(detailAttachs) ){  //今天没有收到该号码 PC_STITCH_DETAIL_ATTACH
                    //，新增入 PC_STITCH_DETAIL_ATTACH
                    PcStitchDetailAttach detailAttach = new PcStitchDetailAttach();
                    BeanUtil.copyProperties(stitchDto, detailAttach);
                    detailAttach.setSeqNo(barcodeDto.getSizeSeq());//鞋码
                    detailAttach.setSlipNo(slipNo);
                    detailAttach.setSlipDate(LocalDate.from(now));
                    detailAttach.setQty(barcodeDto.getCaseQty());
                    detailAttach.setStkName("荣信");
                    detailAttach.setUpdateDate(now);
                    detailAttach.setSysDate(now);
                    detailAttach.setSysUser(request.getCollectPos());
                    detailAttach.setUpdateUser(request.getCollectPos());
                    count4 = detailAttachMapper.insert(detailAttach);
                }else if(ObjectUtils.isNotEmpty(detailAttachs)){  //今天收到该号码 PC_STITCH_DETAIL_ATTACH
                    //更新用量 PC_STITCH_DETAIL_ATTACH
                    PcStitchDetailAttach attach = detailAttachs.get(0);
                    attach.setQty(attach.getQty() + barcodeDto.getCaseQty());
                    attach.setUpdateUser(request.getCollectPos());
                    count4 = detailAttachMapper.updateQty(attach);
                }else{
                    throw new ServiceErrorException("鞋面入库明细表查找异常");
                }
            }else{
                throw new ServiceErrorException("鞋面入库表查找异常");
            }

                long executionTime = System.currentTimeMillis() - start;
                System.out.println(executionTime + "ms");

            if(count1>0 && count2>0 && count3>0 && count4>0 ){
                return ResponseInfo.ok("收料成功");
            }else{
                throw  new ServiceErrorException("收料失败");
            }


        } finally {
                // 检查并释放锁
                String existingValue = (String) redisTemplate.opsForValue().get(lockKey);
                if (lockValue.equals(existingValue)) {
                    redisTemplate.delete(lockKey); // 释放锁
                }
        }

    }

    /**
     * 扫码:发料
     *
     * @param request
     * @param language
     * @return
     */
    @Override
    @Transactional
    public ResponseInfo stitchScanOut(StitchScanRequest request, String language) {
        String companyId = UserIdThread.get().getCompanyId();
        if (request.getBarcode() == null) {
            throw  new ServiceErrorException("条码不能为空!");
        }
        if(request.getCollectPos() == null){
            throw  new ServiceErrorException("设备编号不能为空！");
        }
        if(!request.getProcessName().equals("针车")){
            throw  new ServiceErrorException("请选择采集类别！");
        }
        if(request.getFlag() == null || !request.getFlag().equals("O")){
            throw  new ServiceErrorException("请选择发料类型！");
        }

        /*获取扫描的数据*/
        PcStitchBarcodeHeadDto barcodeDto = pcStitchBarcodeHeadMapper.getPcStitchBarcodeHead(companyId,request.getBarcode());
        //判断条码是否正确
        if (barcodeDto == null) {
            throw  new ServiceErrorException("未在本系统找到该条码!");
        }
        if(barcodeDto.getPrintFlag() == null){
            throw  new ServiceErrorException("未在本系统找到该条码打印标记，请检查！");
        }
        if(barcodeDto.getInFlag() == null){
            throw  new ServiceErrorException("该条码未入库，请先做入库处理！");
        }
        //查询是否扫描过
        PcStitchBarcodeCollect collect = pcStitchBarcodeHeadMapper.getPcStitchBarcodeCollect(request);
        if(collect != null && collect.getSlipType() != null && !collect.getSlipType().equals("O")){
            throw  new ServiceErrorException("发料：该条码已扫过!");
        }

        /*处理收集数据*/
        //扫描头和扫描明细
        PcStitchBarcodeDto stitchDto = new PcStitchBarcodeDto();
        BeanUtils.copyProperties(barcodeDto, stitchDto);
        LocalDateTime now = LocalDateTime.now();
        stitchDto.setCompanyId(companyId);
        stitchDto.setOutFlag("Y");
        stitchDto.setOutQty(barcodeDto.getCaseQty());
        stitchDto.setOutTime(now);
        stitchDto.setSlipType(request.getFlag());
        stitchDto.setQty(barcodeDto.getCaseQty());//明细收集的数量
        stitchDto.setCollectPos(request.getCollectPos());
        stitchDto.setStkName("荣信");
        stitchDto.setPart("鞋面");
        stitchDto.setDeptNo(request.getDeptNo());
        stitchDto.setDeptName(request.getDeptName());
        stitchDto.setCollectType("S");
        stitchDto.setLsNo(barcodeDto.getLsNo());

        //上锁
        String lockKey = "StitchScan:" + companyId + ":" + request.getFlag() + ":" + barcodeDto.getLotNo() + ":" + barcodeDto.getDeptNo() + ":" + barcodeDto.getSizeNo() ;
        String lockValue = UUID.randomUUID().toString();
        Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 2, TimeUnit.SECONDS);
        if (!isLocked) {
            throw new ServiceErrorException("系统处理数据中,请稍后重试!");
        }

        try {
            long start = System.currentTimeMillis();

            /*处理收集表*/
            //1.更新标签头表 PC_STITCH_BARCODE_HEAD
            int count1 = pcStitchBarcodeHeadMapper.updatePcStitchBarcodeHeadByScan(stitchDto);
            //加入收集明细表
            //2.新增收集表 PC_STITCH_BARCODE_COLLECT
            int count2 = 0;
            try {
                count2 = pcStitchBarcodeHeadMapper.insertPcStitchBarcodeCollect(stitchDto);
            } catch (Exception e) {
                log.info("插入收集明细表失败！该条码已扫过");
                throw new ServiceErrorException("该条码已扫过");
            }

            // 获取指令号码
            List<PcLotDetailDto2> codeDetails = pcLotHeadMapper.getCodeDetails4(stitchDto.getLotNo(), companyId,stitchDto.getSizeNo());
            if(ObjectUtils.isEmpty(codeDetails)){
                throw new ServiceErrorException("指令" + stitchDto.getLotNo() + "没有尺码映射");
            }

            /*获取鞋面收发数据*/
            /*查询针车入库表是否已经存在：（缴库单位，指令，收发料，今天）有没有入库*/
            //3.查询 PC_STITCH_DETAIL 有没有数据
            List<PcStitchDetail> details= detailMapper.queryStitchDetail2(stitchDto);
            int count3 = 0;
            int count4 = 0;
            if(ObjectUtils.isEmpty(details)) {  //今天还没有收 PC_STITCH_DETAIL
                // 新增 PC_STITCH_DETAIL
                PcStitchDetail detail = new PcStitchDetail();
                BeanUtil.copyProperties(stitchDto, detail);
                detail.setSlipDate(LocalDate.from(now));
                detail.setSysDate(now);
                detail.setSysUser(request.getCollectPos());
                detail.setOutDept(0);
                detail.setPrintFlag(null);
                detail.setUpdateUser(request.getCollectPos());
                String slipNo = redisService.slipNoCreatByTime("XM");  //第一次创建slipNo
                detail.setSlipNo(slipNo);
                detail.updateQty(codeDetails.get(0).getRowNum(),stitchDto.getCaseQty());
                count3 = detailMapper.insert(detail);
                //新增 PC_STITCH_DETAIL_ATTACH
                PcStitchDetailAttach attach = new PcStitchDetailAttach();
                BeanUtil.copyProperties(stitchDto, attach);
                attach.setSeqNo( barcodeDto.getSizeSeq());  //鞋码序号
                attach.setSlipNo(slipNo);
                attach.setSlipDate(LocalDate.from(now));
                attach.setUpdateDate(now);
                attach.setSysDate(now);
                attach.setSysUser(request.getCollectPos());
                attach.setUpdateUser(request.getCollectPos());
                attach.setQty(barcodeDto.getCaseQty()); //和收集表中扫到的的用量保持一致
                attach.setStkName("荣信");
                count4 = detailAttachMapper.insert(attach);
            }else if(ObjectUtils.isNotEmpty(details)){  //今天收了 PC_STITCH_DETAIL
                //更新 PC_STITCH_DETAIL
                PcStitchDetail detail = details.get(0);
                detail.setUpdateUser(request.getCollectPos());
                detail.updateQty(codeDetails.get(0).getRowNum(),stitchDto.getCaseQty());
                String slipNo = detail.getSlipNo(); //取已有的slipNo
                count3 = detailMapper.updateQty(detail);
                // 查询 PC_STITCH_DETAIL_ATTACH 有没有数据 （缴库单位，指令，收发料，今天，鞋码）
                //4. 判断这个鞋码有没有收到
                stitchDto.setSlipNo(slipNo);
                List<PcStitchDetailAttach> detailAttachs = detailAttachMapper.queryStitchDetailAttach(stitchDto);
                if(ObjectUtils.isEmpty(detailAttachs) ){  //今天没有收到该号码 PC_STITCH_DETAIL_ATTACH
                    //，新增入 PC_STITCH_DETAIL_ATTACH
                    PcStitchDetailAttach detailAttach = new PcStitchDetailAttach();
                    BeanUtil.copyProperties(stitchDto, detailAttach);
                    detailAttach.setSeqNo(barcodeDto.getSizeSeq());//鞋码
                    detailAttach.setSlipNo(slipNo);
                    detailAttach.setSlipDate(LocalDate.from(now));
                    detailAttach.setQty(barcodeDto.getCaseQty());
                    detailAttach.setStkName("荣信");
                    detailAttach.setUpdateDate(now);
                    detailAttach.setSysDate(now);
                    detailAttach.setSysUser(request.getCollectPos());
                    detailAttach.setUpdateUser(request.getCollectPos());
                    count4 = detailAttachMapper.insert(detailAttach);
                }else if(ObjectUtils.isNotEmpty(detailAttachs)){  //今天收到该号码 PC_STITCH_DETAIL_ATTACH
                    //更新用量 PC_STITCH_DETAIL_ATTACH
                    PcStitchDetailAttach attach = detailAttachs.get(0);
                    attach.setQty(attach.getQty() + barcodeDto.getCaseQty());
                    attach.setUpdateUser(request.getCollectPos());
                    count4 = detailAttachMapper.updateQty(attach);
                }else{
                    throw new ServiceErrorException("鞋面入库明细表查找异常");
                }
            }else{
                throw new ServiceErrorException("鞋面入库表查找异常");
            }

            long executionTime = System.currentTimeMillis() - start;
            System.out.println(executionTime + "ms");

            if(count1>0 && count2>0 && count3>0 && count4>0 ){
                return ResponseInfo.ok("发料成功");
            }else{
                throw  new ServiceErrorException("发料失败");
            }


        } finally {
            // 检查并释放锁
            String existingValue = (String) redisTemplate.opsForValue().get(lockKey);
            if (lockValue.equals(existingValue)) {
                redisTemplate.delete(lockKey); // 释放锁
            }
        }
    }

    /**
     * 打单据
     *
     * @param request
     * @param language
     * @return
     */
    @Override
    @Transactional
    public ResponseInfo stitchPrint(StitchScanRequest request, String language) {
        //上锁
        String lockKey = "stitchPrint:" + request.getFlag();
        String lockValue = UUID.randomUUID().toString();
        Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 5, TimeUnit.SECONDS);
        if (!isLocked) {
            //throw new ServiceErrorException("系统处理数据中,请稍后重试!");
            throw  new ServiceErrorException(getMessage("系统处理数据中,请稍后重试！","11.Hệ thống xử lý dữ liệu, xin vui lòng thử lại sau",language));
        }

        try {
            String companyId = UserIdThread.get().getCompanyId();
            request.setCompanyId(companyId);

            //1.缴库单位+指令++这台pos机器上的未打印单据----现在不看pos机器编码了
            List<StitchCollectPrint2Dto> printList2 = pcStitchBarcodeHeadMapper.queryCollectStitchOfDepetALot(request);

            if (ObjectUtils.isEmpty(printList2)) {
                //throw new ServiceErrorException("暂未对指令进行收发料操作！");
                throw  new ServiceErrorException(getMessage("暂未对指令进行收发料操作！","18.Không có lệnh gửi và nhận hoạt động",language));
            }

            //2.缴库单位+指令+号码分组++这台pos机器上的未打印单据----现在不看pos机器编码了
            List<StitchCollectPrintDto> printList = pcStitchBarcodeHeadMapper.queryCollectStitchOfDepetALotASize(request);

            //3.把指令+仓库相同的放到同一个类，和他们对应的码数放进匹配的list里面
            LocalDateTime now = LocalDateTime.now();
            if (ObjectUtils.isNotEmpty(printList2)) {
                if (ObjectUtils.isNotEmpty(printList)) {
                    for (StitchCollectPrint2Dto dto2 : printList2) {
                        List<StitchCollectLotDto> dateList = dto2.getDateList();
                        if (dateList == null) {
                            dateList = new ArrayList<>(); // 初始化一个新的 ArrayList
                            dto2.setDateList(dateList); // 设置到 dto2
                        }
                        dto2.setTime(now);
                        String key2 = dto2.getDeptNo() + dto2.getLotNo(); // 计算 key2 一次
                        for (StitchCollectPrintDto dto : printList) {
                            String key = dto.getDeptNo() + dto.getLotNo();
                            if (key.equals(key2)) {
                                StitchCollectLotDto stitchCollectLotDto = new StitchCollectLotDto();
                                BeanUtils.copyProperties(dto, stitchCollectLotDto);
                                stitchCollectLotDto.setPart(getMessage("鞋面","Đôi giày gặp nhau",language));
                                dateList.add(stitchCollectLotDto);
                            }
                        }
                        //加三个空隔得远一点
                        //printList2.addAll(Arrays.asList(new StitchCollectPrint2Dto()));
                    }
                }
            }

            //批量更新状态--已经打印面单
            int count1 = pcStitchBarcodeHeadMapper.updatePcStitchBarcodeCollect(request, now);

            if (count1 > 0) {
                return ResponseInfo.ok(printList2);
            } else {
                //throw new ServiceErrorException("打印失败");
                throw  new ServiceErrorException(getMessage("打印失败","19.In lỗi",language));
            }
        } finally {
            // 检查并释放锁
            String existingValue = (String) redisTemplate.opsForValue().get(lockKey);
            if (lockValue.equals(existingValue)) {
                redisTemplate.delete(lockKey); // 释放锁
            }
        }
    }

    /**
     * 扫码查询
     *
     * @param request
     * @param language
     * @return
     */
    @Override
    public ResponseInfo stitchScanQuery(StitchScanRequest request, String language) {
        /*获取扫描的数据*/
        String companyId = UserIdThread.get().getCompanyId();
        PcStitchBarcodeHeadDto barcodeDto = pcStitchBarcodeHeadMapper.getPcStitchBarcodeHead(companyId,request.getBarcode());
        PcStitchBarcodeDto stitchDto = new PcStitchBarcodeDto();
        BeanUtils.copyProperties(barcodeDto, stitchDto);
        stitchDto.setPart(getMessage("鞋面","Đôi giày gặp nhau",language));

        //查询这个pos机器获得的数据，该收集表中该（部门+指令+收发料类型+未打印单据）的总数----现在不看pos机器编码了
        PcStitchBarcodeDto printLot = pcStitchBarcodeHeadMapper.queryCollectStitchByLot(stitchDto);
        int qtyCount = stitchDto.getCaseQty();
        if (printLot != null){
            Integer qty = printLot.getQty();
            qtyCount = qty == null ? barcodeDto.getCaseQty() : (qty + barcodeDto.getCaseQty());
        }

        HashMap mapResult = new HashMap<>();
        mapResult.put("barcodeDto", stitchDto);
        //累计收发料双数
        mapResult.put("qtyCount", qtyCount);
        return ResponseInfo.ok(mapResult);
    }

    /**
     * 测试过收进来的鞋码
     *
     * @param request
     * @param language
     * @return
     */
    @Override
    @Transactional
    public ResponseInfo stitch(StitchScanRequest request, String language) {
        return null;
    }

    public Map<String, PcLotSizeQtyDto> getQtyBySize2(String lotNo, String companyId) {
        // 获取指令号码
        List<PcLotDetailDto> codeDetails = pcLotHeadMapper.getCodeDetails(lotNo, companyId);

        // 把 qty 数量和号码对接上
        Map<String, PcLotSizeQtyDto> map = new HashMap<>();
        for (PcLotDetailDto dto : codeDetails) {
            if (dto != null) {
                PcLotSizeQtyDto pcLotSizeQtyDto = new PcLotSizeQtyDto();
                pcLotSizeQtyDto.setOrdQty(dto.getOrdQty().intValue());;
                pcLotSizeQtyDto.setSizeSeq(Integer.valueOf(dto.getSeqNo()));
                pcLotSizeQtyDto.setSizeNo(dto.getSizeNo());
                pcLotSizeQtyDto.setQtyNeed(dto.getTotalQty().intValue()); // 拿到这个号码本来该拿到的数量
                pcLotSizeQtyDto.setQtyFlag("qty" + (map.size() + 1));  // 设定这个号码对应的 qty
                pcLotSizeQtyDto.setI(map.size() + 1); // 设定第几个
                map.put(dto.getSizeNo(), pcLotSizeQtyDto);
            }
        }
        return map;
    }

    /**
     * 抓取数据库触发器的自定义的异常提示
     * @param e
     * @param errorMessagePrefix
     */
    private void handleDatabaseException(UncategorizedSQLException e, String errorMessagePrefix) {
        Throwable cause = e.getCause();
        if (cause instanceof SQLException && "45000".equals(((SQLException) cause).getSQLState())) {
            String errorMessage = cause.getMessage();
            log.error(errorMessagePrefix + ": " + errorMessage);
            throw new ServiceErrorException(errorMessage);
        } else {
            log.error("数据库操作异常: ", e);
            throw e; // 或者根据需要抛出其他异常
        }
    }

    // 添加辅助方法用于获取不同语言的消息
    private String getMessage(String chinese, String vietnamese, String language) {
        if ("vi".equals(language)) {
            return vietnamese;
        }
        return chinese;
    }

}